package main

import (
	"github.com/jacktea/z-cron/global"
	"github.com/jacktea/z-cron/utils"
	kp "gopkg.in/alecthomas/kingpin.v2"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

var (
	app = kp.New("task", "任务服务").Author("zzg").Version("1.0.0")
	cmd *exec.Cmd

	//cfgPath = app.Flag("conf", "配置文件路径").Short('c').String()
	logPath = app.Flag("logs", "日志文件路径").Short('l').String()
	pidPath = app.Flag("pid", "pid文件路径").Short('p').String()

	startCmd   = app.Command("start", "启动")
	stopCmd    = app.Command("stop", "停止")
	statusCmd  = app.Command("status", "状态")
	reStartCmd = app.Command("restart", "重启")
	//reloadCmd  = app.Command("reload", "重新加载配置文件")
	runCmd = app.Command("run", "运行").Default().Hidden()
)

func getLogPath() string {
	lPath := *logPath
	if lPath == "" {
		lPath = filepath.Join(utils.GetAppPath(), "logs", filepath.Base(os.Args[0])+".log")
	} else {
		lPath = utils.GetFileAbs(lPath)
	}
	utils.CreateDirIfNotExist(lPath)
	return lPath
}
func getPidPath() string {
	p := *pidPath
	if p == "" {
		p = filepath.Join(utils.GetAppPath(), filepath.Base(os.Args[0])+".pid")
	} else {
		p = utils.GetFileAbs(p)
	}
	utils.CreateDirIfNotExist(p)
	return p
}

func status() bool {
	pidPath := getPidPath()
	var cmd *exec.Cmd
	b, err := ioutil.ReadFile(pidPath)
	if err == nil {
		if !utils.IsWindows() {
			cmd = exec.Command("/bin/sh", "-c", "ps -ax | awk '{ print $1 }' | grep "+string(b))
		} else {
			cmd = exec.Command("tasklist")
		}
		out, _ := cmd.Output()
		if strings.Index(string(out), string(b)) > -1 {
			return true
		}
	}
	return false
}

func start() {
	osArgs := make([]string, 0)
	osArgs = append(osArgs, os.Args[0])
	// osArgs = append(osArgs, "run")
	osArgs = append(osArgs, os.Args[2:]...)
	pidPath := getPidPath()
	if status() {
		log.Printf(" %s is running", osArgs[0])
		return
	}
	cmd := exec.Command(osArgs[0], osArgs[1:]...)
	cmd.Start()
	if cmd.Process.Pid > 0 {
		log.Printf("start ok , pid:%v , path: %v ", cmd.Process.Pid, pidPath)
		d1 := []byte(strconv.Itoa(cmd.Process.Pid))
		ioutil.WriteFile(filepath.Join(pidPath), d1, 0600)
	} else {
		log.Println("start error")
	}
}

func restart() {
	if !status() {
		start()
	} else {
		stop(false)
		for i := 0; i < 30; i++ {
			if status() {
				time.Sleep(time.Second * 1)
				log.Println("stop waiting...")
			}
		}
		if status() {
			stop(true)
		}
		start()
	}
}

func stop(force bool) {
	pidPath := getPidPath()
	p := os.Args[0]
	if !status() {
		log.Printf(" %s is not running", p)
		return
	}
	var c *exec.Cmd
	var err error
	if utils.IsWindows() {
		p := strings.Split(p, `\`)
		c = exec.Command("taskkill", "/F", "/IM", p[len(p)-1])
	} else {
		b, err := ioutil.ReadFile(pidPath)
		if err == nil {
			if force {
				c = exec.Command("/bin/bash", "-c", `kill -9 `+string(b))
			} else {
				c = exec.Command("/bin/bash", "-c", `kill `+string(b))
			}
		} else {
			log.Fatal("stop error,pid file does not exist")
		}
	}
	err = c.Run()
	if err != nil {
		log.Println("stop exec error,", err)
	} else {
		log.Println("stop exec ok")
	}
}

func defaultRun() {
	global.Start(getLogPath())
}

func main() {
	switch kp.MustParse(app.Parse(os.Args[1:])) {
	case startCmd.FullCommand():
		start()
		os.Exit(0)
	case stopCmd.FullCommand():
		stop(false)
		os.Exit(0)
	case reStartCmd.FullCommand():
		restart()
		os.Exit(0)
	case statusCmd.FullCommand():
		if status() {
			log.Printf("%s is running", os.Args[0])
		} else {
			log.Printf("%s is not running", os.Args[0])
		}
		os.Exit(0)
	default:
		defaultRun()
	}

}
